# -*- coding:utf-8 -*-
"""
Database Model for post to catalog.
"""

import peewee

from config import CMS_CFG
from torcms.core import tools
from torcms.model.category_model import MCategory
from torcms.model.core_tab import TabPost, TabPost2Tag, TabTag


class MPost2Catalog:
    """
    Database Model for post to catalog.
    """

    @staticmethod
    def just_query_all():
        """
        Just Query all the records from TabPost2Tag.
        """
        recs = TabPost2Tag.select()
        return recs

    @staticmethod
    def del_by_uid(uid):
        """
        Just Query all the records from TabPost2Tag.
        """
        entry = TabPost2Tag.delete().where(TabPost2Tag.uid == uid)
        try:
            entry.execute()
            return True
        except Exception as err:
            print(repr(err))
            return False

    @staticmethod
    def query_all():
        """
        Query all the records from TabPost2Tag.
        """
        recs = TabPost2Tag.select(
            TabPost2Tag,
            TabTag.kind.alias('tag_kind'),
        ).join(TabTag, on=(TabPost2Tag.tag_id == TabTag.uid))
        return recs

    @staticmethod
    def remove_relation(post_id, tag_id):
        """
        Delete the record of post 2 tag.
        """
        entry = TabPost2Tag.delete().where(
            (TabPost2Tag.post_id == post_id) & (TabPost2Tag.tag_id == tag_id)
        )
        entry.execute()
        MCategory.update_count(tag_id)

    @staticmethod
    def remove_tag(tag_id):
        """
        Delete the records of certain tag.
        """
        entry = TabPost2Tag.delete().where(TabPost2Tag.tag_id == tag_id)
        entry.execute()

    @staticmethod
    def query_by_catid(catid):
        """
        Query the records by ID of catalog.
        """
        return TabPost2Tag.select().where(TabPost2Tag.tag_id == catid)

    @staticmethod
    def query_postinfo_by_cat(catid):
        cat_con = TabPost2Tag.tag_id == catid
        recs = (
            TabPost.select()
            .join(
                TabPost2Tag,
                on=((TabPost.uid == TabPost2Tag.post_id) & (TabPost.valid == 1)),
            )
            .where(cat_con)
        )
        return recs

    @staticmethod
    def query_by_post(postid):
        """
        Query records by post.
        """
        return (
            TabPost2Tag.select()
            .where(TabPost2Tag.post_id == postid)
            .order_by(TabPost2Tag.order)
        )

    @staticmethod
    def __get_by_info(post_id, catalog_id):
        """
        Geo the record by post and catalog.
        """
        recs = TabPost2Tag.select().where(
            (TabPost2Tag.post_id == post_id) & (TabPost2Tag.tag_id == catalog_id)
        )

        if recs.count() == 1:
            return recs.get()
        elif recs.count() > 1:
            # return the first one, and delete others.
            out_rec = None
            for rec in recs:
                if out_rec:
                    entry = TabPost2Tag.delete().where(TabPost2Tag.uid == rec.uid)
                    entry.execute()
                else:
                    out_rec = rec
            return out_rec
        return None

    @staticmethod
    def query_count():
        """
        The count of post2tag.
        """
        recs = TabPost2Tag.select(
            TabPost2Tag.tag_id, peewee.fn.COUNT(TabPost2Tag.tag_id).alias('num')
        ).group_by(TabPost2Tag.tag_id)
        return recs

    @staticmethod
    def update_field(uid, post_id=None, tag_id=None, par_id=None):
        """
        Update the field of post2tag.
        """
        if post_id:
            entry = TabPost2Tag.update(post_id=post_id).where(TabPost2Tag.uid == uid)
            entry.execute()

        if tag_id:
            entry2 = TabPost2Tag.update(
                par_id=tag_id[:2] + '00',
                tag_id=tag_id,
            ).where(TabPost2Tag.uid == uid)
            entry2.execute()
        if par_id:
            entry2 = TabPost2Tag.update(par_id=par_id).where(TabPost2Tag.uid == uid)
            entry2.execute()

    @staticmethod
    def add_record(post_id, catalog_id, order=0):
        """
        Create the record of post 2 tag, and update the count in g_tag.
        """

        rec = MPost2Catalog.__get_by_info(post_id, catalog_id)
        if rec:
            entry = TabPost2Tag.update(
                order=order,
                # For migration. the value should be added when created.
                par_id=rec.tag_id[:2] + '00',
            ).where(TabPost2Tag.uid == rec.uid)
            entry.execute()
        else:
            TabPost2Tag.create(
                uid=tools.get_uuid(),
                par_id=catalog_id[:2] + '00',
                post_id=post_id,
                tag_id=catalog_id,
                order=order,
            )

        MCategory.update_count(catalog_id)

    @staticmethod
    def count_of_certain_category(cat_id, tag=''):
        """
        Get the count of certain category.
        """

        if cat_id.endswith('00'):
            # The first level category, using the code bellow.
            cat_con = TabPost2Tag.par_id == cat_id
        else:
            cat_con = TabPost2Tag.tag_id == cat_id
        #
        # if tag:
        #     condition = {'def_tag_arr': [tag]}
        #     recs = TabPost2Tag.select().join(
        #         TabPost,
        #         on=(TabPost.uid == TabPost2Tag.post_id)).where(
        #         cat_con & (TabPost.valid == 1) & TabPost.extinfo.contains(condition)).distinct()
        # else:
        #     recs = TabPost2Tag.select().join(
        #         TabPost,
        #         on=(TabPost.uid == TabPost2Tag.post_id)).where(cat_con &
        #                                                        (TabPost.valid == 1)).distinct()
        if tag:
            condition = {'def_tag_arr': [tag]}
            recs = (
                TabPost.select()
                .join(TabPost2Tag, on=(TabPost.uid == TabPost2Tag.post_id))
                .where(
                    cat_con & (TabPost.valid == 1) & TabPost.extinfo.contains(condition)
                )
                .distinct()
            )

        else:
            recs = (
                TabPost.select()
                .join(TabPost2Tag, on=(TabPost.uid == TabPost2Tag.post_id))
                .where(cat_con & (TabPost.valid == 1))
                .distinct()
            )
        return recs.count()

    @staticmethod
    def query_pager_by_slug(slug, current_page_num=1, tag='', order=False):
        """
        Query pager via category slug.
        """
        cat_rec = MCategory.get_by_slug(slug)
        if cat_rec:
            cat_id = cat_rec.uid
        else:
            return None

        # The flowing code is valid.
        if cat_id.endswith('00'):
            # The first level category, using the code bellow.
            cat_con = TabPost2Tag.par_id == cat_id
        else:
            cat_con = TabPost2Tag.tag_id == cat_id
        if order:
            sort_criteria = TabPost.order.asc()
            if tag:
                condition = {'def_tag_arr': [tag]}
                recs = (
                    TabPost.select()
                    .join(TabPost2Tag, on=(TabPost.uid == TabPost2Tag.post_id))
                    .where(
                        cat_con
                        & (TabPost.valid == 1)
                        & TabPost.extinfo.contains(condition)
                    )
                    .order_by(sort_criteria, TabPost.time_create.asc())
                    .paginate(current_page_num, CMS_CFG['list_num'])
                    .distinct()
                )

            else:
                recs = (
                    TabPost.select()
                    .join(TabPost2Tag, on=(TabPost.uid == TabPost2Tag.post_id))
                    .where(cat_con & (TabPost.valid == 1))
                    .order_by(sort_criteria, TabPost.time_create.asc())
                    .paginate(current_page_num, CMS_CFG['list_num'])
                    .distinct()
                )
        else:
            sort_criteria = TabPost.time_update.desc()

            if tag:
                condition = {'def_tag_arr': [tag]}
                recs = (
                    TabPost.select()
                    .join(TabPost2Tag, on=(TabPost.uid == TabPost2Tag.post_id))
                    .where(
                        cat_con
                        & (TabPost.valid == 1)
                        & TabPost.extinfo.contains(condition)
                    )
                    .order_by(sort_criteria)
                    .paginate(current_page_num, CMS_CFG['list_num'])
                    .distinct()
                )

            else:
                recs = (
                    TabPost.select()
                    .join(TabPost2Tag, on=(TabPost.uid == TabPost2Tag.post_id))
                    .where(cat_con & (TabPost.valid == 1))
                    .order_by(sort_criteria)
                    .paginate(current_page_num, CMS_CFG['list_num'])
                    .distinct()
                )

        return recs

    @staticmethod
    def query_by_entity_uid(idd, kind=''):
        """
        Query post2tag by certain post.
        """

        if kind == '':
            return (
                TabPost2Tag.select(
                    TabPost2Tag,
                    TabTag.slug.alias('tag_slug'),
                    TabTag.name.alias('tag_name'),
                )
                .join(TabTag, on=(TabPost2Tag.tag_id == TabTag.uid))
                .where((TabPost2Tag.post_id == idd) & (TabTag.kind != 'z'))
                .order_by(TabPost2Tag.order)
            )
        return (
            TabPost2Tag.select(
                TabPost2Tag,
                TabTag.slug.alias('tag_slug'),
                TabTag.name.alias('tag_name'),
            )
            .join(TabTag, on=(TabPost2Tag.tag_id == TabTag.uid))
            .where((TabTag.kind == kind) & (TabPost2Tag.post_id == idd))
            .order_by(TabPost2Tag.order)
        )

    @staticmethod
    def query_by_id(idd):
        """
        Alias of `query_by_entity_uid`.
        """
        return MPost2Catalog.query_by_entity_uid(idd)

    @staticmethod
    def get_first_category(app_uid):
        """
        Get the first, as the uniqe category of post.
        """
        recs = MPost2Catalog.query_by_entity_uid(app_uid).objects()
        if recs.count() > 0:
            return recs.get()

        return None

    def query_list_by_uid(slug, uid=False):
        cat_rec = MCategory.get_by_slug(slug)
        if cat_rec:
            cat_id = cat_rec.uid
        else:
            return None

        # The flowing code is valid.
        if cat_id.endswith('00'):
            # The first level category, using the code bellow.
            cat_con = TabPost2Tag.par_id == cat_id
        else:
            cat_con = TabPost2Tag.tag_id == cat_id

        if uid:
            recs = (
                TabPost.select()
                .join(
                    TabPost2Tag,
                    on=((TabPost.uid == TabPost2Tag.post_id) & (TabPost.valid == 1)),
                )
                .where(cat_con)
                .order_by(TabPost.uid, TabPost.time_create.asc())
            )
        else:
            recs = (
                TabPost.select()
                .join(
                    TabPost2Tag,
                    on=((TabPost.uid == TabPost2Tag.post_id) & (TabPost.valid == 1)),
                )
                .where(cat_con)
                .order_by(TabPost.order.asc(), TabPost.time_create.asc())
            )

        return recs
